package com.auditlog.datasource.execute;

import com.auditlog.datasource.StatementProxy;
import com.auditlog.datasource.context.ConnectionContext;
import com.auditlog.sql.factory.SqlRunnerFactory;
import com.auditlog.sql.factory.SqlRunnerFactoryRegistry;
import com.auditlog.sql.runner.SqlRunner;
import com.auditlog.datasource.context.ContextHolder;
import com.auditlog.datasource.struct.RecordImage;
import lombok.extern.slf4j.Slf4j;
import com.auditlog.datasource.struct.SqlMeta;

import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

@Slf4j
public class SingleExecutor<T, S extends Statement> extends BaseExecutor<T, S> {

    private SqlRunner sqlRunner;

    private RecordImage recordImage;

    public SingleExecutor(StatementProxy<S> statementProxy, StatementCallback<T, S> statementCallback, SqlMeta sqlMeta) {
        super(statementProxy, statementCallback, sqlMeta);
    }

    @Override
    public void beforeExecute() throws SQLException {
        SqlMeta sqlMeta = super.getSqlMeta();
        ConnectionContext connectionContext = ContextHolder.getConnectionContext();
        List<net.sf.jsqlparser.statement.Statement> statements = sqlMeta.getStatements();
        net.sf.jsqlparser.statement.Statement statement = statements.get(0);
        SqlRunnerFactory sqlRunnerFactory = SqlRunnerFactoryRegistry.getInstance().support(statement);
        this.sqlRunner = sqlRunnerFactory.getRunner(this.getStatementProxy(), statement);
        if (!connectionContext.isError()) {
            try {
                this.sqlRunner.validate();
                this.recordImage = this.sqlRunner.beforeImage();
            } catch (Exception e) {
                handleException(connectionContext, e);
            }
        }
    }

    @Override
    public void afterExecute() throws SQLException {
        ConnectionContext connectionContext = ContextHolder.getConnectionContext();
        if (!connectionContext.isError() && this.sqlRunner != null) {
            try {
                sqlRunner.afterImage(this.recordImage);
            } catch (Exception e) {
                handleException(connectionContext, e);
            }
        }
        ContextHolder.getExecuteContext().addRecordImage(recordImage);
    }
}
